package org.springframework.web.servlet.handler;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistration;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import com.gitee.hermer.boot.jee.commons.collection.CollectionUtils;
import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;
import com.gitee.hermer.engine.jars.app.sdk.EngineAppClassLoader;


public class EngineMappingRegistrationCache extends UtilsContext{

	private final Map<RequestMappingInfo, MappingRegistration<RequestMappingInfo>> registry = new HashMap<RequestMappingInfo, MappingRegistration<RequestMappingInfo>>();
	private final Map<RequestMappingInfo, HandlerMethod> mappingLookup = new LinkedHashMap<RequestMappingInfo, HandlerMethod>();
	private final MultiValueMap<String, RequestMappingInfo> urlLookup = new LinkedMultiValueMap<String, RequestMappingInfo>();
	private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();

	private static EngineMappingRegistrationCache instance= null;

	private EngineMappingRegistrationCache (){}  
	public static synchronized EngineMappingRegistrationCache getInstance() {  
		if (instance == null) {  
			instance = new EngineMappingRegistrationCache();
		}  
		return instance;  
	}  


	public <T extends RequestMappingInfo> void register(T mappingInfo,HandlerMethod method,List<String> directUrls,CorsConfiguration corsConfig,String name){

		String cacheKey = "this"; // 容器号
		if(method.getClassLoader() != null && method.getClassLoader() instanceof EngineAppClassLoader){
			cacheKey = method.getCacheKey();
		}
		info("Scan[%s] to:"+"Mapped \"" + mappingInfo + "\" onto " + method+"- Success[%s]",cacheKey,true);
		this.mappingLookup.put(mappingInfo, method);
		for (String url : directUrls) {
			this.urlLookup.add(url, mappingInfo);
		}
		if(corsConfig != null)
			this.corsLookup.put(method, corsConfig);
		MappingRegistration<T> mappingRegistration = new MappingRegistration<T>(mappingInfo,method,directUrls,name);
		this.registry.put(mappingInfo, (MappingRegistration<RequestMappingInfo>)mappingRegistration);
	}

	public void unregister(String cacheKey){

		synchronized (urlLookup) {
			List<RequestMappingInfo> rmappingList = CollectionUtils.newArrayList();
			for (RequestMappingInfo info : mappingLookup.keySet()) {
				if(StringUtils.isNotBlank(mappingLookup.get(info).getCacheKey()) && cacheKey.contentEquals(mappingLookup.get(info).getCacheKey())){
					rmappingList.add(info);
				}
			}
			info(rmappingList.toString());
			List<HandlerMethod> rhandlerList = CollectionUtils.newArrayList();
			for (RequestMappingInfo mappingInfo : rmappingList) {
				rhandlerList.add(mappingLookup.get(mappingInfo));
			}
			List<String> rurlList = CollectionUtils.newArrayList();
			for (String url : urlLookup.keySet()) {
				List<RequestMappingInfo> infos = urlLookup.get(url);
				for (RequestMappingInfo info : infos) {
					if(rmappingList.contains(info) && !rurlList.contains(url)){
						rurlList.add(url);
					}
				}
			}
			for (String url : rurlList) {
				info("Remove[%s] to:  Key:[%s] - Success[%s]",cacheKey,url,true);
				urlLookup.remove(url);
			}
			
			for (RequestMappingInfo info : rmappingList) {
				registry.remove(info);
				mappingLookup.remove(info);
			}
			for (HandlerMethod method : rhandlerList) {
				corsLookup.remove(method);
			}
		}
	}

	public Map<RequestMappingInfo, MappingRegistration<RequestMappingInfo>> getRegistry() {
		return registry;
	}
	public Map<RequestMappingInfo, HandlerMethod> getMappingLookup() {
		return mappingLookup;
	}
	public MultiValueMap<String, RequestMappingInfo> getUrlLookup() {
		return urlLookup;
	}
	public Map<HandlerMethod, CorsConfiguration> getCorsLookup() {
		return corsLookup;
	}





}
